/**
 ******************************************************************************
 * @file           : bsp_can.c
 * @brief          : CAN Driver Implementation (STM32H7xx)
 ******************************************************************************
 * @attention
 *
 * CAN总线驱动程序实现文件
 * 提供CAN通信功能
 * 支持标准帧和扩展帧、过滤器配置
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./BSP/CAN/bsp_can.h"
#include "./BSP/CAN/bsp_can_config.h"
#include <string.h>

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define CAN_RX_BUF_MASK     (CAN_RX_BUF_SIZE - 1)

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static FDCAN_HandleTypeDef sg_can_handle;                      /*!< CAN句柄 */
static volatile uint8_t sg_can_initialized = 0;               /*!< 初始化标志 */
static volatile CAN_State_e sg_can_state = CAN_STATE_IDLE;    /*!< CAN状态 */

/* 接收缓冲区 */
static CAN_Message_t sg_can_rx_buf[CAN_RX_BUF_SIZE];          /*!< 接收缓冲区 */
static volatile uint16_t sg_can_rx_head = 0;                  /*!< 读指针 */
static volatile uint16_t sg_can_rx_tail = 0;                  /*!< 写指针 */

/* Private function prototypes -----------------------------------------------*/
static void can_msp_init(void);
static void can_msp_deinit(void);
static uint8_t can_is_datetime_valid(const CAN_Message_t *msg);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       CAN底层初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        配置GPIO和时钟
 */
static void can_msp_init(void)
{
    GPIO_InitTypeDef gpio_init = {0};

    /* 使能GPIO时钟 */
    CAN_TX_GPIO_CLK_ENABLE();
    CAN_RX_GPIO_CLK_ENABLE();

    /* 配置TX引脚 */
    gpio_init.Pin = CAN_TX_GPIO_PIN;
    gpio_init.Mode = GPIO_MODE_AF_PP;
    gpio_init.Pull = GPIO_NOPULL;
    gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
    gpio_init.Alternate = GPIO_AF9_CAN1;
    HAL_GPIO_Init(CAN_TX_GPIO_PORT, &gpio_init);

    /* 配置RX引脚 */
    gpio_init.Pin = CAN_RX_GPIO_PIN;
    gpio_init.Mode = GPIO_MODE_AF_PP;
    HAL_GPIO_Init(CAN_RX_GPIO_PORT, &gpio_init);

    /* 使能CAN时钟 */
    CAN_CANx_CLK_ENABLE();

    /* 配置中断 */
    HAL_NVIC_SetPriority(CAN_RX_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(CAN_RX_IRQn);
}

/**
 * @brief       CAN底层反初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        关闭GPIO和时钟
 */
static void can_msp_deinit(void)
{
    HAL_GPIO_DeInit(CAN_TX_GPIO_PORT, CAN_TX_GPIO_PIN);
    HAL_GPIO_DeInit(CAN_RX_GPIO_PORT, CAN_RX_GPIO_PIN);
    HAL_NVIC_DisableIRQ(CAN_RX_IRQn);
}

/**
 * @brief       验证CAN消息有效性
 *
 * @param[in]   msg - CAN消息指针
 *
 * @retval      uint8_t - 1=有效, 0=无效
 *
 * @note        检查消息参数范围
 */
static uint8_t can_is_datetime_valid(const CAN_Message_t *msg)
{
    if (msg == NULL)
    {
        return 0;
    }

    if (msg->dlc > 8)
    {
        return 0;
    }

    if (msg->ide > 1 || msg->rtr > 1)
    {
        return 0;
    }

    return 1;
}

/* Public functions ----------------------------------------------------------*/

void can_init(void)
{
    if (sg_can_initialized)
    {
        return;
    }

    can_msp_init();

    sg_can_handle.Instance = CAN_CANx;
    sg_can_handle.Init.ClockDivider = FDCAN_CLOCK_DIV1;
    sg_can_handle.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
    sg_can_handle.Init.Mode = CAN_MODE;
    sg_can_handle.Init.AutoRetransmission = ENABLE;
    sg_can_handle.Init.TransmitPause = DISABLE;
    sg_can_handle.Init.ProtocolException = DISABLE;
    sg_can_handle.Init.NominalPrescaler = CAN_PRESCALER;
    sg_can_handle.Init.NominalTimeSeg1 = CAN_TIME_SEG1;
    sg_can_handle.Init.NominalTimeSeg2 = CAN_TIME_SEG2;
    sg_can_handle.Init.NominalSyncJumpWidth = CAN_SJW;
    sg_can_handle.Init.DataPrescaler = 1;
    sg_can_handle.Init.DataTimeSeg1 = FDCAN_DATA_SEG1_1TQ;
    sg_can_handle.Init.DataTimeSeg2 = FDCAN_DATA_SEG2_1TQ;
    sg_can_handle.Init.DataSyncJumpWidth = FDCAN_DATA_SJW_1TQ;
    sg_can_handle.Init.StdFiltersNbr = 1;
    sg_can_handle.Init.ExtFiltersNbr = 0;
    sg_can_handle.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;

    if (HAL_FDCAN_Init(&sg_can_handle) != HAL_OK)
    {
        log_e("CAN initialization failed");
        return;
    }

    /* 配置过滤器 - 接收所有消息 */
    FDCAN_FilterTypeDef filter_config = {0};
    filter_config.IdType = FDCAN_STANDARD_ID;
    filter_config.FilterIndex = 0;
    filter_config.FilterType = FDCAN_FILTER_MASK;
    filter_config.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
    filter_config.FilterID1 = 0x000;
    filter_config.FilterID2 = 0x000;

    if (HAL_FDCAN_ConfigFilter(&sg_can_handle, &filter_config) != HAL_OK)
    {
        log_e("CAN filter configuration failed");
        return;
    }

    /* 启动CAN */
    if (HAL_FDCAN_Start(&sg_can_handle) != HAL_OK)
    {
        log_e("CAN start failed");
        return;
    }

    /* 使能接收中断 */
    if (HAL_FDCAN_ActivateNotification(&sg_can_handle, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
    {
        log_e("CAN interrupt activation failed");
        return;
    }

    sg_can_initialized = 1;
    sg_can_state = CAN_STATE_IDLE;
    log_i("CAN initialized successfully");
}

void can_deinit(void)
{
    if (!sg_can_initialized)
    {
        return;
    }

    HAL_FDCAN_Stop(&sg_can_handle);
    HAL_FDCAN_DeInit(&sg_can_handle);
    can_msp_deinit();

    sg_can_initialized = 0;
    sg_can_state = CAN_STATE_IDLE;
    log_i("CAN deinitialized");
}

CAN_Error_e can_filter_config(uint32_t id, uint32_t mask)
{
    if (!sg_can_initialized)
    {
        log_e("CAN not initialized");
        return CAN_ERROR_HAL;
    }

    FDCAN_FilterTypeDef filter_config = {0};
    filter_config.IdType = FDCAN_STANDARD_ID;
    filter_config.FilterIndex = 0;
    filter_config.FilterType = FDCAN_FILTER_MASK;
    filter_config.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
    filter_config.FilterID1 = id;
    filter_config.FilterID2 = mask;

    if (HAL_FDCAN_ConfigFilter(&sg_can_handle, &filter_config) != HAL_OK)
    {
        log_e("CAN filter configuration failed");
        return CAN_ERROR_HAL;
    }

    log_i("CAN filter configured: ID=0x%03X, Mask=0x%03X", id, mask);
    return CAN_OK;
}

CAN_Error_e can_filter_disable(void)
{
    if (!sg_can_initialized)
    {
        log_e("CAN not initialized");
        return CAN_ERROR_HAL;
    }

    FDCAN_FilterTypeDef filter_config = {0};
    filter_config.IdType = FDCAN_STANDARD_ID;
    filter_config.FilterIndex = 0;
    filter_config.FilterType = FDCAN_FILTER_MASK;
    filter_config.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
    filter_config.FilterID1 = 0x000;
    filter_config.FilterID2 = 0x000;

    if (HAL_FDCAN_ConfigFilter(&sg_can_handle, &filter_config) != HAL_OK)
    {
        log_e("CAN filter disable failed");
        return CAN_ERROR_HAL;
    }

    log_i("CAN filter disabled - receiving all messages");
    return CAN_OK;
}

CAN_Error_e can_send(const CAN_Message_t *msg)
{
    FDCAN_TxHeaderTypeDef tx_header = {0};

    if (!sg_can_initialized)
    {
        log_e("CAN not initialized");
        return CAN_ERROR_HAL;
    }

    if (!can_is_datetime_valid(msg))
    {
        log_e("Invalid CAN message");
        return CAN_ERROR_PARAM;
    }

    tx_header.Identifier = msg->id;
    tx_header.IdType = msg->ide ? FDCAN_EXTENDED_ID : FDCAN_STANDARD_ID;
    tx_header.TxFrameType = msg->rtr ? FDCAN_REMOTE_FRAME : FDCAN_DATA_FRAME;
    tx_header.DataLength = msg->dlc << 16;
    tx_header.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
    tx_header.BitRateSwitch = FDCAN_BRS_OFF;
    tx_header.FDFormat = FDCAN_CLASSIC_CAN;
    tx_header.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
    tx_header.MessageMarker = 0;

    sg_can_state = CAN_STATE_TX;

    if (HAL_FDCAN_AddMessageToTxFifoQ(&sg_can_handle, &tx_header, (uint8_t *)msg->data) != HAL_OK)
    {
        log_e("CAN send failed");
        sg_can_state = CAN_STATE_IDLE;
        return CAN_ERROR_HAL;
    }

    sg_can_state = CAN_STATE_IDLE;
    log_d("CAN message sent: ID=0x%X, DLC=%d", msg->id, msg->dlc);
    return CAN_OK;
}

CAN_Error_e can_send_std(uint32_t id, const uint8_t *data, uint8_t len)
{
    CAN_Message_t msg = {0};

    if (len > 8)
    {
        log_e("Invalid data length");
        return CAN_ERROR_PARAM;
    }

    msg.id = id & 0x7FF;
    msg.ide = 0;
    msg.rtr = 0;
    msg.dlc = len;
    memcpy(msg.data, data, len);

    return can_send(&msg);
}

CAN_Error_e can_send_ext(uint32_t id, const uint8_t *data, uint8_t len)
{
    CAN_Message_t msg = {0};

    if (len > 8)
    {
        log_e("Invalid data length");
        return CAN_ERROR_PARAM;
    }

    msg.id = id & 0x1FFFFFFF;
    msg.ide = 1;
    msg.rtr = 0;
    msg.dlc = len;
    memcpy(msg.data, data, len);

    return can_send(&msg);
}

CAN_Error_e can_receive(CAN_Message_t *msg)
{
    if (!sg_can_initialized)
    {
        log_e("CAN not initialized");
        return CAN_ERROR_HAL;
    }

    if (msg == NULL)
    {
        log_e("Invalid pointer");
        return CAN_ERROR_PARAM;
    }

    if (sg_can_rx_head == sg_can_rx_tail)
    {
        return CAN_ERROR_EMPTY;
    }

    memcpy(msg, &sg_can_rx_buf[sg_can_rx_head], sizeof(CAN_Message_t));
    sg_can_rx_head = (sg_can_rx_head + 1) & CAN_RX_BUF_MASK;

    return CAN_OK;
}

uint16_t can_available(void)
{
    return (sg_can_rx_tail - sg_can_rx_head) & CAN_RX_BUF_MASK;
}

CAN_State_e can_get_state(void)
{
    return sg_can_state;
}

uint8_t can_is_bus_off(void)
{
    if (!sg_can_initialized)
    {
        return 0;
    }

    return (sg_can_handle.State == HAL_FDCAN_STATE_ERROR) ? 1 : 0;
}

void can_print_status(void)
{
    const char *state_str[] = {"IDLE", "BUSY", "TX", "RX", "ERROR"};

    log_i("=== CAN Status ===");
    log_i("State: %s", state_str[sg_can_state]);
    log_i("Initialized: %s", sg_can_initialized ? "Yes" : "No");
    log_i("RX Messages: %d", can_available());
    log_i("Bus Off: %s", can_is_bus_off() ? "Yes" : "No");
}

void can_print_message(const CAN_Message_t *msg)
{
    if (msg == NULL)
    {
        return;
    }

    log_i("CAN Message: ID=0x%X %s, DLC=%d, Data=[%02X %02X %02X %02X %02X %02X %02X %02X]",
          msg->id,
          msg->ide ? "EXT" : "STD",
          msg->dlc,
          msg->data[0], msg->data[1], msg->data[2], msg->data[3],
          msg->data[4], msg->data[5], msg->data[6], msg->data[7]);
}

/* CAN接收中断处理 */
void CAN_RX_IRQHandler(void)
{
    FDCAN_RxHeaderTypeDef rx_header = {0};
    uint8_t rx_data[8] = {0};

    if (HAL_FDCAN_GetRxMessage(&sg_can_handle, FDCAN_RX_FIFO0, &rx_header, rx_data) == HAL_OK)
    {
        uint16_t next_tail = (sg_can_rx_tail + 1) & CAN_RX_BUF_MASK;

        if (next_tail != sg_can_rx_head)
        {
            sg_can_rx_buf[sg_can_rx_tail].id = rx_header.Identifier;
            sg_can_rx_buf[sg_can_rx_tail].ide = (rx_header.IdType == FDCAN_EXTENDED_ID) ? 1 : 0;
            sg_can_rx_buf[sg_can_rx_tail].rtr = (rx_header.RxFrameType == FDCAN_REMOTE_FRAME) ? 1 : 0;
            sg_can_rx_buf[sg_can_rx_tail].dlc = rx_header.DataLength >> 16;
            memcpy(sg_can_rx_buf[sg_can_rx_tail].data, rx_data, 8);

            sg_can_rx_tail = next_tail;
            sg_can_state = CAN_STATE_RX;
        }
    }
}
